package chelydra.sharelydra.client.friend;

import chelydra.sharelydra.client.webservice.WebserviceException;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Hashtable;
import java.util.Set;

import chelydra.sharelydra.client.Core;
import java.util.Collection;
import java.util.Vector;

/**
 *
 * @author Pierre-Élie Fauché
 */
public class FriendManager {
	/**
	 * Time To Live for updates of our friends list in minutes.
	 * Before expiration of this TTL, no updates occur if asked.
	 */
	public static int UPDATE_TTL = 0; // todo remplacer le ttl d'update mis pour les tests dans friendmanager

	private Date lastUpdate;
	private Map<String, Friend> friends;

	public FriendManager() {
		this.lastUpdate = new Date(0);
		this.friends = new Hashtable(0);
	}

	public Collection<Friend> getFriendsForLogins(Collection<String> logins) {
		Collection<Friend> fr = new Vector();
		Iterator i = logins.iterator();
		while (i.hasNext()) {
			String login = (String)i.next();
			fr.add(this.friends.get(login));
		}

		return fr;
	}

	public Friend getFriendsForLogins(String login) {
		return this.friends.get(login);
	}

	public Collection<Friend> getFriendsOfGroup(String selectedGroup) {
		Collection<String> logins = Core.getApplication().getDatabaseManager().getLoginsOfGroup(selectedGroup);
		return this.getFriendsForLogins(logins);
	}

	public Collection<Friend> getNonFriendsOfGroup(String selectedGroup) {
		Collection<String> memberLogins = Core.getApplication().getDatabaseManager().getLoginsOfGroup(selectedGroup);

		Collection<String> nonMembersLogins = (Vector)new Vector(this.friends.keySet()).clone();
		nonMembersLogins.removeAll(memberLogins);

		return this.getFriendsForLogins(nonMembersLogins);
	}

	public void notifyFriend(String friendSelected, String file) {
		try {
			Core.getApplication().getWebserviceManager().doNotify(file, friendSelected);

			Notification newNote = new Notification(new Date(), Notification.SENT_NOTIFY_FILE_FRIEND,
							file, "", "", this.friends.get(friendSelected).getNickname());
			Core.getApplication().getDatabaseManager().addNewNotification(newNote);
			Core.getApplication().getView().updateNotifications();
			
		} catch (WebserviceException ex) {
			ex.printStackTrace(System.err);
		}
	}

	public void notifyGroup(String groupSelected, String file) {
		String[] logins = Core.getApplication().getDatabaseManager().getLoginsOfGroup(groupSelected).toArray(new String[0]);

		StringBuffer sb = new StringBuffer();
		for (int i=0; i<logins.length; i++) {
			if (i>0)
				sb.append("<=>");
			sb.append(logins[i]);
		}
		try {
			Core.getApplication().getWebserviceManager().doNotify(file, sb.toString());

			Notification newNote = new Notification(new Date(), Notification.SENT_NOTIFY_FILE_GROUP,
							file, "", "", groupSelected);
			Core.getApplication().getDatabaseManager().addNewNotification(newNote);
			Core.getApplication().getView().updateNotifications();

		} catch (WebserviceException ex) {
			ex.printStackTrace(System.err);
		}
	}

	/**
	 * Initiate the update of the list of friends with the server.
	 * The update is actually done only after a certain time after the last update (threshold)
	 */
	public void updateFriends() {
		int ttlMilliseconds = UPDATE_TTL*60*1000;
		Date threshold = new Date(this.lastUpdate.getTime()+ttlMilliseconds);
		if (threshold.before(new Date())) {
			try {
				Core.getApplication().getWebserviceManager().doFriends();
			} catch (WebserviceException ex) {
				// TODO handle Exception when asking the friends update
				ex.printStackTrace(System.err);
			}
		}
	}

	/**
	 * Updates the list of friends based on the Map given as parameter.
	 * This Map is issued from the webservice, data is given by the server.
	 * @param newFriends Map à jour des amis
	 */
	public void updateFriends(Map<String,Friend> newFriends) {
		Set<String> oldFriendKeys = this.friends.keySet();

		if (!newFriends.isEmpty()) {
			Set<String> newFriendKeys = newFriends.keySet();
			oldFriendKeys.removeAll(newFriendKeys);
		}

		Iterator i = oldFriendKeys.iterator();
		while (i.hasNext()) {
			Core.getApplication().getDatabaseManager().deleteFriend((String)i.next());
		}

		this.friends = newFriends;
		this.lastUpdate = new Date();

		Core.getApplication().getView().updateFriends(this.friends.values());
		Core.getApplication().getView().updateGroupsTable();
	}

	public void searchFriends(String keywordsString) {
		try {
			Core.getApplication().getWebserviceManager().doSearchFriends(keywordsString);
		} catch (WebserviceException ex) {
			// TODO handle Exception when searching friends
			ex.printStackTrace(System.err);
		}
	}

	/**
	 * Returns the ips and ports of connected friends
	 * @return Map (Hashtable) with ips as keys and ports as values
	 */
	public Map<String,Integer> getIpsAndPorts() {
		Map<String,Integer> ips = new Hashtable();

		Iterator i = this.friends.values().iterator();
		while (i.hasNext()) {
			Friend f = (Friend)i.next();
			if (f.isConnected()) {
				ips.put(f.getIp(), f.getPort());
			}
		}

		return ips;
	}

	public void updateSearchFriends(Collection<Map<String,String>> usersFound) {
		Iterator i = usersFound.iterator();
		while (i.hasNext()) {
			Map<String,String> userAttributes = (Map<String,String>)i.next();
			if (this.friends.containsKey(userAttributes.get("login"))) {
				userAttributes.put("status", "friend");
			} else {
				userAttributes.put("status", "");
			}
		}

		Core.getApplication().getView().updateSearchFriends(usersFound);
	}

	public void updateGroups() {
		Core.getApplication().getView().updateGroupsTable();
	}

	public boolean isMyFriend(String login) {
		return this.friends.containsKey(login);
	}

	public String getIpForLogin(String login){
		return this.friends.get(login).getIp();
	}

	public int getPortForLogin(String login){
		return this.friends.get(login).getPort();
	}

	public Collection<Friend> getFriends() {
		return this.friends.values();
	}

	public Collection<Friend> getConnectedFriends() {
		Collection<Friend> connected = new Vector();
		Iterator i = this.friends.values().iterator();
		while (i.hasNext()) {
			Friend f = (Friend)i.next();
			if (f.isConnected())
				connected.add(f);
		}
		return connected;
	}

	public String getNicknameForIp(String ip) {
		Iterator i = this.friends.values().iterator();
		while (i.hasNext()) {
			Friend f = (Friend)i.next();
			if (f.getIp().contentEquals(ip))
				return f.getNickname();
		}
		return "someone";
	}

}
